// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.commons.ui.swt;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Sash;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 1 2006-09-29 17:06:40Z qiang.zhang $
 * 
 */
public class MergeComposite extends Composite {

    private static final int HORIZONTAL = 1;

    private static final int VERTICAL = 2;

    private static final double HSPLIT = 0.5;

    private static final double VSPLIT = 0.3;

    private Composite fLeft;

    private Composite fRight;

    private Composite fCenter;

    private Button fCenterButton;

    private Cursor fNormalCursor;

    private GridLayout gridLayout;

    private GridData gridData;

    /**
     * Qiang.Zhang.Adolf@gmail.com MergeComposite constructor comment.
     * 
     * @param parent
     * @param style
     */
    public MergeComposite(Composite parent, int style) {
        super(parent, style);
        gridLayout = new GridLayout();
        gridLayout.numColumns = 3;
        setLayout(gridLayout);
        gridData = new GridData(GridData.FILL_BOTH);
        setLayoutData(gridData);
        createControls();
    }

    private void createControls() {
        fLeft = createPart(this);
        fCenter = createCenter(this);
        fRight = createPart(this);
    }

    private Composite createPart(Composite parent) {
        final Composite part = new Composite(parent, SWT.BORDER);
        gridLayout = new GridLayout();
        gridData = new GridData(GridData.FILL_BOTH);
        part.setLayout(gridLayout);
        part.setLayoutData(gridData);
        return part;
    }

    @SuppressWarnings("restriction")//$NON-NLS-1$
    private Composite createCenter(Composite parent) {
        // final Canvas canvas = new BufferedCanvas(parent, SWT.BORDER) {
        //
        // public void doPaint(GC gc) {
        // paintCenter(this, gc);
        // }
        // };
        Composite fCenter = new Composite(parent, SWT.BORDER);
        gridData = new GridData(GridData.FILL_BOTH);
        gridLayout = new GridLayout();
        gridLayout.marginBottom = 0;
        gridLayout.marginHeight = 0;
        gridLayout.marginLeft = 0;
        gridLayout.marginRight = 0;
        gridLayout.marginTop = 0;
        gridLayout.marginWidth = 0;

        fCenter.setLayout(gridLayout);
        fCenter.setLayoutData(gridData);
        new HoverResizer(fCenter, HORIZONTAL);
        fCenterButton = new Button(fCenter, SWT.PUSH);
        if (fNormalCursor == null)
            fNormalCursor = new Cursor(fCenter.getDisplay(), SWT.CURSOR_ARROW);
        fCenterButton.setCursor(fNormalCursor);
        fCenterButton.setText("<"); //$NON-NLS-1$
        fCenterButton.pack();
        fCenterButton.setVisible(true);
        return fCenter;
    }

    private Cursor fVSashCursor;

    private Cursor fHSashCursor;

    private Cursor fHVSashCursor;

    class HoverResizer extends MouseAdapter implements MouseMoveListener {

        Control fControl;

        int fX, fY;

        int fWidth1, fWidth2;

        int fHeight1, fHeight2;

        int fDirection;

        boolean fLiveResize;

        boolean fIsDown;

        private double fHSplit;

        private double fVSplit;

        public HoverResizer(Control c, int dir) {
            fDirection = dir;
            fControl = c;
            fLiveResize = !(fControl instanceof Sash);
            updateCursor(c, dir);
            fControl.addMouseListener(this);
            fControl.addMouseMoveListener(this);
            fControl.addDisposeListener(new DisposeListener() {

                public void widgetDisposed(DisposeEvent e) {
                    fControl = null;
                }
            });
        }

        @Override
        public void mouseDoubleClick(MouseEvent e) {
            if ((fDirection & HORIZONTAL) != 0)
                fHSplit = HSPLIT;
            if ((fDirection & VERTICAL) != 0)
                fVSplit = VSPLIT;
            MergeComposite.this.layout(true);
        }

        @Override
        public void mouseDown(MouseEvent e) {
            Composite parent = fControl.getParent();

            Point s = parent.getSize();
            Point ys = fLeft.getSize();
            Point ms = fRight.getSize();

            fWidth1 = ys.x;
            fWidth2 = ms.x;
            fHeight1 = fLeft.getLocation().y;
            fHeight2 = s.y - (fLeft.getLocation().y + ys.y);

            fX = e.x;
            fY = e.y;
            fIsDown = true;
        }

        @Override
        public void mouseUp(MouseEvent e) {
            fIsDown = false;
            if (!fLiveResize)
                resize(e);
        }

        public void mouseMove(MouseEvent e) {
            if (fIsDown && fLiveResize)
                resize(e);
        }

        private void resize(MouseEvent e) {
            int dx = e.x - fX;
            int dy = e.y - fY;

            int centerWidth = fCenter.getSize().x;

            if (fWidth1 + dx > centerWidth && fWidth2 - dx > centerWidth) {
                fWidth1 += dx;
                fWidth2 -= dx;
                if ((fDirection & HORIZONTAL) != 0)
                    fHSplit = (double) fWidth1 / (double) (fWidth1 + fWidth2);
            }
            if (fHeight1 + dy > centerWidth && fHeight2 - dy > centerWidth) {
                fHeight1 += dy;
                fHeight2 -= dy;
                if ((fDirection & VERTICAL) != 0)
                    fVSplit = (double) fHeight1 / (double) (fHeight1 + fHeight2);
            }

            MergeComposite.this.layout(true);
            fControl.getDisplay().update();
        }
    }

    void updateCursor(Control c, int dir) {
        if (!(c instanceof Sash)) {
            Cursor cursor = null;
            switch (dir) {
            case VERTICAL:
                if (fVSashCursor == null)
                    fVSashCursor = new Cursor(c.getDisplay(), SWT.CURSOR_SIZENS);
                cursor = fVSashCursor;
                break;
            case HORIZONTAL:
                if (fHSashCursor == null)
                    fHSashCursor = new Cursor(c.getDisplay(), SWT.CURSOR_SIZEWE);
                cursor = fHSashCursor;
                break;
            case VERTICAL + HORIZONTAL:
                if (fHVSashCursor == null)
                    fHVSashCursor = new Cursor(c.getDisplay(), SWT.CURSOR_SIZEALL);
                cursor = fHVSashCursor;
                if (fHSashCursor == null)
                    fHSashCursor = new Cursor(c.getDisplay(), SWT.CURSOR_SIZEWE);
                cursor = fHSashCursor;
                break;
            }
            if (cursor != null)
                c.setCursor(cursor);
        }
    }
}
